
#include <i2c.h>
#include <irq.h>
#include <timer.h>
#include <stdio.h>



static u8 			_iicData[IICBUFSIZE];
static volatile int _iicDataCount;
static volatile int _iicStatus;
static volatile int _iicMode;
static int 			_iicPt;

void i2c_init(void) {
	GPECON	 = GPECON & ~(0xf<<28) | (0xa<<28);		// GPE15:IICSDA , GPE14:IICSCL

	irq_request( 27, i2c_irq );
	INTMSK	&= ~(1<<27);

	IICCON	 = (1<<7) | (1<<6) | (1<<5) | (0x1);	// Enable ACK, Prescaler IICCLK=PCLK/512, Enable interrupt, Transmit clock value 
	IICADD   = 0x10;								// Slave Address [7:1]
	IICSTAT	 = 0x10;								// IIC bus data output enable(Rx/Tx)
	IICLC	 = (1<<2)|(3);				   			// SDAOUT has 5clock cycle delay
}

void i2c_master_transmit(u8 slave_id, u8 reg_addr, u8 data) {
	
	//int delay;

	_iicMode      = WRDATA;
	_iicPt        = 0;
	_iicData[0]   = reg_addr;
	_iicData[1]   = data;
	_iicDataCount = 2;

	// Master Tx mode, Start(Write), IIC-bus data output enable
	// Bus arbitration sucessful, Address as slave status flag Cleared,
	// Address zero status flag cleared, Last received bit is 0	
    IICDS         = slave_id;
	IICSTAT		  = 0xf0;
	IICCON		 &= ~(1<<4);

	while( _iicDataCount != -1 );
}

void i2c_master_receive(u8 slave_id,u8 reg_addr,u8 *data)
{

	/*IIC Slave Addr Write + IIC Reg Addr Write */ 
	_iicMode      = SETRDADDR;
	_iicPt        = 0;
	_iicData[0]   = reg_addr;
	_iicDataCount = 1;

	IICDS         = slave_id;
	IICSTAT		  = 0xf0;//Master Tx, Start
	IICCON		 &= ~(1<<4);//Resumes IIC operation. 

	while( _iicDataCount != -1 );

	_iicMode		= RDDATA;
	_iicPt			= 0;
	_iicDataCount = 1;

	IICDS 			= slave_id;
	IICSTAT 		= 0xb0;
	IICCON			&= ~(1<<4);//Resumes IIC operation. 

	while( _iicDataCount != -1 );

	*data = _iicData[1];
}

void i2c_irq(void) {

	u32 iicSt, delay;

	ClearPending(1<<27);
	iicSt    = IICSTAT; 
	INTMSK |= (1<<27);

	if(iicSt & 0x8){}           //When bus arbitration is failed.
	if(iicSt & 0x4){}           //When a slave address is matched with IICADD
	if(iicSt & 0x2){}           //When a slave address is 0000000b
	if(iicSt & 0x1){}           //When ACK isn't received

	switch(_iicMode) {
		case WRDATA:
			if((_iicDataCount--)==0) {
				IICSTAT = 0xd0;                		// stop MasTx condition 
				IICCON  = 0xaf;//&= ~(1<<4);                	// resumes IIC operation.

				udelay(1000);
				// The pending bit will not be set after issuing stop condition.
				break;    
			}

			IICDS = _iicData[_iicPt++];        		// _iicData[0] has dummy.
			for( delay = 0; delay < 10; ++delay );	// for setup time until rising edge of IICSCL
			IICCON = 0xaf;//&= ~(1<<4);                     	// resumes IIC operation.

			break;
		case RDDATA:
			if((_iicDataCount--)==0) 
			{ 
			_iicData[_iicPt++] = IICDS; 

			IICSTAT = 0x90; //Stop MasRx condition 
			IICCON = 0xaf;//&= ~(1<<4); //Resumes IIC operation. 
			udelay(1000); //Wait until stop condtion is in effect. 
			//Too long time... 
			//The pending bit will not be set after issuing stop condition. 
			break; 
			} 
			_iicData[_iicPt++] = IICDS; //The last data has to be read with no ack. 

			if((_iicDataCount)==0) 
			IICCON = 0x2f; //Resumes IIC operation with NOACK. ???? 
			else 
			IICCON = 0xaf;//&= ~(1<<4); //Resumes IIC operation with ACK 
			break; 
		case SETRDADDR: 
		
		if((_iicDataCount--)==0) 
		break; //IIC operation is stopped because of IICCON[4] 
		IICDS = _iicData[_iicPt++]; 
		for(delay=0;delay<10;delay++); //For setup time until rising edge of IICSCL 
			IICCON = 0xaf;//&= ~(1<<4); //Resumes IIC operation. 
		break; 
			

		default:
			break;      
	}

	INTMSK &= ~(1<<27);
}
